共计 4395 个字符,预计需要花费 11 分钟才能阅读完成。
远程线程注入汇编代码
重定位问题
编译器在处理调用的 API 时,由于 API 地址不确定,他就会定义一个全局变量,然后在运行时由系统去填充全局变量(放入 API 的实现位置)
注入代码,而实际上调用这个 call MessageBox,实际上 CALL 的是一个偏移地址,
injectCode proc
int 3
push 0
push 0
push 0
push 0
call MessageBox
retn 4 ; 这里是一个线程回调函数,有一个参数 DWORD WINAPI ThreadProc(LPVOID lpParameter);
injectCode endp
注入程序中,在注入程序中 MessageBox 这个偏移位置是正确的 API 位置
被注入程序,而在被注入程序这个偏移是一个错误的位置(无效地址)
模拟系统这个功能,首先申请一个全局变量,然后在模拟操作系统把 API 地址填入全局变量
; 获取自己模块基质
invoke GetModuleHandle,offset USER32_NAME
.if eax==NULL
jmp Inject_End
.endif
mov @hUser32,eax
; 获取 API 地址
invoke GetProcAddress,@hUser32,offset MSGBOX_NAME
.if eax==NULL
jmp Inject_End
.endif
mov @hMsgBoxAddr,eax
mov dword ptr [MessageBoxAddr],eax
; 正常情况(MessageBoxAddr - @hUser32)+ 对方 User32 模块基质
需要注意的是,写入的位置是一个代码区没有权限写入,要不然就写入数据区,要不然就修改内存属性
injectCode proc
int 3
push 0
push 0
push 0
push 0
call dword ptr [MessageBoxAddr]
retn 4 ; 这里是一个线程回调函数,有一个参数 DWORD WINAPI ThreadProc(LPVOID lpParameter);
MessageBoxAddr dd ?
injectCode endp
call dword ptr [MessageBoxAddr],但是这样会变成 Call 一个绝对地址取内容,而绝对地址是由注入方生成的
注入方
被注入方
所以要解决这个问题,我们就要使用相互地址,而不是绝对地址,这个就叫代码重定位问题
方法一
一个巧妙的方法,通过 CALL 标号 把当前 EIP 当前地址入栈,然后我们直接 POP ebx 出栈把当前地址给 ebx,在用 edx + 偏移这样就可以获取到正确的地址,缺陷就是每次都需要计算
injectCode proc
int 3
push 0
push 0
push 0
push 0
call NEXT
NEXT:
pop ebx
call dword ptr[ebx + 7]
retn 4 ; 这里是一个线程回调函数,有一个参数 DWORD WINAPI ThreadProc(LPVOID lpParameter);
MessageBoxAddr dd ?
injectCode endp
方法二
首先通过被注入程序地址 – 注入程序地址 得到程序的偏移,然后注入程序的地址里面的数据地址 + 程序偏移就是被注入程序的实际位置
injectCode proc
int 3
call NEXT
NEXT:
pop ebx
sub ebx,NEXT
push MB_OK
lea eax,[ebx+Title1]
push eax
lea eax,[ebx+Msg1]
push eax
push NULL
call dword ptr[ebx + MessageBoxAddr]
retn 4 ; 这里是一个线程回调函数,有一个参数 DWORD WINAPI ThreadProc(LPVOID lpParameter);
MessageBoxAddr dd ?
Msg1 db "Hello World",0
Title1 db "51ASM",0
injectCode endp
获取 API 的偏移地址
拿自己的模块基质 减掉 API 地址,得到一个 API 偏移,然后在被注入程序中 加上这个偏移 就是一个正确的 API 地址
(MessageBoxAddr – @hUser32)+ 对方 User32 模块基质
; 获取自己模块基质
invoke GetModuleHandle,offset USER32_NAME
.if eax==NULL
jmp Inject_End
.endif
mov @hUser32,eax
; 获取 API 地址
invoke GetProcAddress,@hUser32,offset MSGBOX_NAME
.if eax==NULL
jmp Inject_End
.endif
mov @hMsgBoxAddr,eax
mov dword ptr [MessageBoxAddr],eax
; 正常情况(MessageBoxAddr - @hUser32)+ 对方 User32 模块基质
调试技巧
INT 3 断点,当被调试进程执行 INT3 指令导致一个异常时,调试器就会捕捉这个异常从而停在断点处
所以在注入的汇编代码写入 INT 3,调试被注入程序时代码注入后会自动停止在 INT 3 的位置
注入代码
.386
.model flat, stdcall ;32 bit memory model
option casemap :none ;case sensitive
include Project1.inc
.code
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke InitCommonControls
invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL
invoke ExitProcess,0
injectCode proc
int 3
call NEXT
NEXT:
pop ebx
sub ebx,NEXT
push MB_OK
lea eax,[ebx+Title1]
push eax
lea eax,[ebx+Msg1]
push eax
push NULL
call dword ptr[ebx + MessageBoxAddr]
retn 4 ; 这里是一个线程回调函数,有一个参数 DWORD WINAPI ThreadProc(LPVOID lpParameter);
MessageBoxAddr dd ?
Msg1 db "Hello World",0
Title1 db "51ASM",0
injectCode endp
Inject proc
LOCAL @hWnd:HWND
LOCAL @dwPid:DWORD
LOCAL @hProcess:HANDLE
LOCAL @lpBuffer:PVOID
LOCAL @dwBytes:PVOID
LOCAL @hThread:HANDLE
LOCAL @hUser32:HANDLE
LOCAL @hMsgBoxAddr:PVOID
LOCAL @dwOld:dword
mov @hWnd,NULL
mov @dwPid,0
mov @hProcess,NULL
mov @lpBuffer,NULL
mov @dwBytes,0
mov @hThread,NULL
mov @hUser32,NULL
mov @hMsgBoxAddr,NULL
mov @dwOld,0
; 获取窗口句柄
invoke FindWindow,NULL,offset WND_NAME
.if eax==NULL
jmp Inject_End
.endif
mov @hWnd,eax
; 获取进程 ID
invoke GetWindowThreadProcessId,@hWnd,addr @dwPid
.if eax==NULL
jmp Inject_End
.endif
; 打开进程
invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,@dwPid
.if eax==NULL
jmp Inject_End
.endif
mov @hProcess,eax
; 申请内存
invoke VirtualAllocEx,@hProcess,NULL,1000h,MEM_COMMIT,PAGE_EXECUTE_READWRITE
.if eax==NULL
jmp Inject_End
.endif
mov @lpBuffer,eax
; 获取自己模块基质
invoke GetModuleHandle,offset USER32_NAME
.if eax==NULL
jmp Inject_End
.endif
mov @hUser32,eax
; 获取 API 地址
invoke GetProcAddress,@hUser32,offset MSGBOX_NAME
.if eax==NULL
jmp Inject_End
.endif
mov @hMsgBoxAddr,eax
invoke VirtualProtect,offset MessageBoxAddr,Inject-MessageBoxAddr,PAGE_EXECUTE_READWRITE,addr @dwOld
.if eax==NULL
jmp Inject_End
.endif
mov eax,@hMsgBoxAddr
mov [MessageBoxAddr],eax
; 正常情况(MessageBoxAddr - @hUser32)+ 对方 User32 模块基质
; 写入汇编代码
invoke WriteProcessMemory,@hProcess,@lpBuffer,offset injectCode,Inject-injectCode,addr @dwBytes
.if eax==0
jmp Inject_End
.endif
; 创建远程线程
invoke CreateRemoteThread,@hProcess,NULL,0,@lpBuffer,NULL,0,NULL
.if eax==0
jmp Inject_End
.endif
; 等待线程结束
; 删除注入代码
Inject_End:
.if @hWnd != NULL
invoke CloseHandle,@hWnd
.endif
.if @hProcess!= NULL
invoke CloseHandle,@hProcess
.endif
.if @hThread!= NULL
invoke CloseHandle,@hThread
.endif
.if @hUser32!= NULL
invoke CloseHandle,@hUser32
.endif
ret
Inject endp
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
mov eax,uMsg
.if eax==WM_INITDIALOG
.elseif eax==WM_COMMAND
mov eax,wParam
.if ax == IDC_BTN1
invoke Inject
.endif
.elseif eax==WM_CLOSE
invoke EndDialog,hWin,0
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
DlgProc endp
end start